package com.yixin.hospital.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.yixin.hospital.entity.domain.User;
import com.yixin.hospital.enums.ResponseCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.yixin.hospital.config.CaffeineConfig.tokenExpirationSec;

@Slf4j
@Component
public class JwtUtil {

    /**
     * 密钥
     */
    private static final String SECRET = "2002C3342AC74078B035D12BF8C8E92D91D6FF059CB03438B8767369FF8E0BEA";


    /**
     * 生成用户token,设置token超时时间
     */
    public static String createToken(User user) {
        //过期时间
        Date expireDate = new Date(System.currentTimeMillis() + tokenExpirationSec * 1000);
        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");
        String token = JWT.create()
                .withHeader(map)
                //将基本信息放到claims中
                .withClaim("userId", user.getId())
                .withClaim("name", user.getName())
                .withExpiresAt(expireDate)
                .withIssuedAt(new Date())
                .sign(Algorithm.HMAC256(SECRET));
        CaffeineUtils.putToken(token, "1");
        return token;
    }

    /**
     * 校验token并解析token
     */
    public static ResponseCodeEnum verifyToken(String token) {
        if (CaffeineUtils.getToken(token) == null) {
            return ResponseCodeEnum.TOKEN_EXP;
        }
        DecodedJWT jwt;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
            jwt = verifier.verify(token);
            long iat = jwt.getClaims().get("iat").asDate().getTime();
            // 昨天生成的token在第二天也视为过期
            long epochMilli = LocalDate.now().atStartOfDay(ZoneOffset.ofHours(8)).toInstant().toEpochMilli();
            if (epochMilli > iat) {
                return ResponseCodeEnum.TOKEN_EXP;
            }
        } catch (TokenExpiredException e) {
            log.error("token 过期:", e);
            return ResponseCodeEnum.TOKEN_EXP;
        } catch (Exception e) {
            log.error("token解码异常:", e);
            return ResponseCodeEnum.ILLEGAL_TOKEN;
        }
        return ResponseCodeEnum.SUCCESS;
    }

    public static String getName(String token) {
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
        DecodedJWT jwt = verifier.verify(token);
        return jwt.getClaims().get("name").asString();
    }

    public static Long getUserId(String token) {
        JWTVerifier verifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
        DecodedJWT jwt = verifier.verify(token);
        return jwt.getClaims().get("userId").asLong();
    }
}
